﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Data;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Reflection;
using Newtonsoft.Json.Serialization;
using NHibernate.Proxy;

namespace Cms.EntLib
{
    public class Json
    {
        public static string ToJson(object obj) {
            return ToJson(obj, false);
        }
        /// <summary>
        /// 要生成JSON 的对象
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="IgnoreCollection">是否忽略集合对象</param>
        /// <returns></returns>
        public static string ToJson(object obj,bool IgnoreCollection)
        {
            StringWriter sw = new StringWriter();
            string[] ExceptMemberName = null;

            JsonSerializer serializer = JsonSerializer.Create(
                 new JsonSerializerSettings
                {
                    //Converters = new JsonConverter[] { new Newtonsoft.Json.Converters.JavaScriptDateTimeConverter() },
                    Converters=new JsonConverter[]{
                        new Newtonsoft.Json.Converters.IsoDateTimeConverter()
                    },
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,//循环引用 忽略
                    NullValueHandling = NullValueHandling.Include,//所有的空值也包含上.
                    ContractResolver = new NHibernateContractResolver(ExceptMemberName, IgnoreCollection)
                }
                );

            using (JsonWriter jsonWriter = new JsonTextWriter(sw))
            {
                jsonWriter.Formatting = Formatting.Indented;
                serializer.Serialize(jsonWriter, obj);
            }
            return sw.ToString();
        }
        public static string ToGridJson(object o, int page, int records, int total)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("{");
            sb.AppendLine("\"page\":" + page + ",");
            sb.AppendLine("\"total\":" + total/records + ",");
            sb.AppendLine("\"records\":" + records + ",");
            sb.AppendLine("\"rows\":");
            string json = ToJson(o,true);
            if (!String.IsNullOrEmpty(json))
                sb.AppendLine(json);
            else
                sb.AppendLine("[]");
            sb.AppendLine("}");
            return sb.ToString();
        }

        public static string ToJson<T>(List<T> list)
        {
            return ToJson((object)list);
        }
        /// <summary>
        /// 将字典列表转成为 JqGrid 所用的JSON
        /// </summary>
        /// <param name="list"></param>
        /// <param name="page"></param>
        /// <param name="records"></param>
        /// <param name="total"></param>
        /// <returns></returns>
        public static string ToGridJson(IList list, int page, int records, int total)
        {
            return ToGridJson((object)list,page,records,total);
            
        }

        /// <summary>
        /// 将对象转成为JQGRID所用的JSON
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="page"></param>
        /// <param name="records"></param>
        /// <param name="total"></param>
        /// <returns></returns>
        public static string ToGridJson<T>(List<T> list, int page, int records, int total)
        {
            return ToGridJson((object)list, page, records, total);            
        }

        public static string DataTableToJson(DataTable dt, int page, int total, int records)
        {

            StringBuilder JsonString = new StringBuilder();
            JsonString.Append("{");
            JsonString.Append("\"page\":" + page + ",");
            JsonString.Append("\"total\":" + total + ",");
            JsonString.Append("\"records\":" + records + ",");
            //-----------rows build
            JsonString.Append("\"rows\":");
            JsonString.Append("[");
            if (dt.Rows.Count > 0)
            {
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    JsonString.Append("{");
                    for (int j = 0; j < dt.Columns.Count; j++)
                    {
                        if (j < dt.Columns.Count - 1)
                        {
                            JsonString.Append("\"" + dt.Columns[j].ColumnName.ToLower() + "\":" + "\"" + StripNoJson(dt.Rows[i][j].ToString()) + "\",");
                        }
                        else if (j == dt.Columns.Count - 1)
                        {
                            JsonString.Append("\"" + dt.Columns[j].ColumnName.ToLower() + "\":" + "\"" + StripNoJson(dt.Rows[i][j].ToString()) + "\"");
                        }
                    }

                    if (i == dt.Rows.Count - 1)
                    {
                        JsonString.Append("}");
                    }
                    else
                    {
                        JsonString.Append("},");
                    }
                }
            }
            JsonString.Append("]");
            JsonString.Append("");
            JsonString.Append("}");
            return JsonString.ToString();
        }
        public static string DataTableToJQTreeGridJson(DataTable dt, string keyfield, string parentfiled, string isleaffield, string parentkey)
        {
            StringBuilder JsonString = new StringBuilder();
            JsonString.Append("{");
            JsonString.Append("\"page\":" + "1" + ",");
            JsonString.Append("\"total\":" + dt.Rows.Count.ToString() + ",");
            JsonString.Append("\"records\":" + dt.Rows.Count.ToString() + ",");
            //-----------rows build
            JsonString.Append("\"rows\":");
            JsonString.Append("[");
            //DataRow[] drs=
            JsonString.Append(DataTableToJQTreeGridJson_Row(dt, keyfield, parentfiled, isleaffield, parentkey).TrimEnd(','));
            JsonString.Append("]");

            JsonString.Append("");
            JsonString.Append("}");
            return JsonString.ToString();
        }
        public static string ChangeString(string str)
        {
            //str含有HTML标签的文本
            str = str.Replace("<", "&lt;");
            str = str.Replace(">", "&gt;");
            str = str.Replace(" ", "&nbsp;");
            str = str.Replace("\n", "<br>");
            str = str.Replace("&", "&amp;");
            return str;
        }
        public static string StripNoJson(object value)
        {
            string values = "";
            if (value == null)
                values = "";
            else
                values = value.ToString();

            if (values.IndexOf(System.Environment.NewLine) > -1)
            {
                values = values.Replace(System.Environment.NewLine, "\\r\\n");
            }
           /* if (values.IndexOf("\n") >= 0)  //解决JSON字符串含回车时的“未终止的字符串常量”问题
            {
                values = values.Replace("\n", "\\n");
            }
            else if (values.IndexOf("\r") >= 0)
            {
                values = values.Replace("\r", "\\r");
            }*/
            else if (values.IndexOf('"') >= 0)  //解决"造成json字符串断层的问题，使用中文的”解决或单引号解决
            {
                values = values.Replace("\"", "\\\"");
            }
            else if (values.IndexOf("'") > -1)
            {
                values = values.Replace("'", "\'");
            }
            else if (values.IndexOf('\\') > -1)
            {
                values = values.Replace("\\", "\\\\");
            }
            //values = ChangeString(values);
            return values;
        }
        public static string StripNoJson(string values)
        {
            if (values.IndexOf(System.Environment.NewLine) > -1)
            {
                values = values.Replace(System.Environment.NewLine, "\\r\\n");
            }
            if (values.IndexOf("\n") >= 0)  //解决JSON字符串含回车时的“未终止的字符串常量”问题
            {
                values = values.Replace("\n", "\\n");
            }
            else if (values.IndexOf("\r") >= 0)
            {
                values = values.Replace("\r", "\\r");
            }
            else if (values.IndexOf('"') >= 0)  //解决"造成json字符串断层的问题，使用中文的”解决或单引号解决
            {
                values = values.Replace('"', '“');
            }
            else if (values.IndexOf("'") > -1)
            {
                values = values.Replace("'", "\'");
            }
            else if (values.IndexOf('\\') > -1)
            {
                values = values.Replace("\\", "\\\\");
            }
            return values;
        }
        private static string ChangeDataValue(string datatype, string FieldValue)
        {
            switch (datatype)
            {
                case "System.Int32":
                case "System.Int64":
                case "System.Double":
                case "System.Int16":
                case "System.Single":
                case "System.Boolean":
                    if (FieldValue == "")
                        FieldValue = "0";
                    break;
                default:
                    break;
            }
            return FieldValue;
        }
        private static bool HaveChild(DataTable dt, string parentKeyField, string KeyValue)
        {
            bool result = false;
            string filter = String.Format(" [{0}]='{1}'", parentKeyField, ChangeDataValue(dt.Columns[parentKeyField].DataType.ToString(), KeyValue));
            DataRow[] drs = dt.Select(filter);
            result = drs != null && drs.Length > 0;
            return result;
        }
        private static void GetLevel(DataTable dt, string keyField, string ParentField, string FieldValue, ref int level)
        {
            string filter = String.Format("{0}='{1}'", keyField, ChangeDataValue(dt.Columns[keyField].DataType.ToString(), FieldValue));
            DataRow[] parents = dt.Select(filter);
            if (parents != null && parents.Length > 0)
            {
                string parent = parents[0][ParentField].ToString();
                level++;
                GetLevel(dt, keyField, ParentField, parent, ref level);
            }
        }
        private static string DataTableToJQTreeGridJson_Row(DataTable dt, string keyfield, string parentfiled, string isleaffield, string value)
        {
            StringBuilder JsonString = new StringBuilder();
            string filter = String.Format(" [{0}]='{1}'", parentfiled, ChangeDataValue(dt.Columns[parentfiled].DataType.ToString(), value));
            if (String.IsNullOrEmpty(value))
            {
                filter = String.Format(" [{0}]='{1}' or isnull([{0}],0)='0'", parentfiled, ChangeDataValue(dt.Columns[parentfiled].DataType.ToString(), value));
            }


            DataRow[] drs = dt.Select(filter);
            for (int i = 0; i < drs.Length; i++)
            {
                JsonString.Append("{");
                bool leafflag = false;
                bool levelflag = false;
                bool haveChildflag = false;

                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    if (!String.IsNullOrEmpty(parentfiled) && parentfiled.ToLower() == dt.Columns[j].ColumnName.ToLower())
                    {
                        string p = drs[i][j].ToString();
                        if (String.IsNullOrEmpty(p))
                            p = "0";
                        JsonString.Append("\"parent\":" + "\"" + StripNoJson(p) + "\",");
                    }
                    else if (!String.IsNullOrEmpty(isleaffield) && isleaffield.ToLower() == dt.Columns[j].ColumnName.ToLower())
                    {
                        JsonString.Append("\"isLeaf\":" + "\"" + StripNoJson(drs[i][j].ToString()) + "\",");
                        leafflag = true;
                    }
                    else if (dt.Columns[j].ColumnName.ToLower() != "level")
                    {
                        JsonString.Append("\"" + dt.Columns[j].ColumnName.ToLower() + "\":" + "\"" + StripNoJson(drs[i][j].ToString()) + "\",");
                    }
                }
                haveChildflag = HaveChild(dt, parentfiled, drs[i][keyfield].ToString());
                if (!leafflag)
                {

                    JsonString.AppendFormat("\"isLeaf\":\"{0}\" ,", (!haveChildflag).ToString().ToLower());
                }
                if (!levelflag)
                {
                    int level = 0;
                    GetLevel(dt, keyfield, parentfiled, drs[i][keyfield].ToString(), ref level);
                    JsonString.AppendFormat("\"level\":{0},", level);
                }
                JsonString.Append("\"expanded\":" + "true");
                if (i == dt.Rows.Count - 1)
                {
                    JsonString.Append("}");
                }
                else
                {
                    JsonString.Append("},");
                }
                if (haveChildflag)
                {
                    string pv = drs[i][keyfield].ToString();
                    JsonString.Append(DataTableToJQTreeGridJson_Row(dt, keyfield, parentfiled, isleaffield, pv));
                }
            }
            return JsonString.ToString();
        }

        public static string TableToEasyUIJson(IList dt)
        {

            StringBuilder JsonString = new StringBuilder();
            int count = 0;
            if (dt != null)
                count = dt.Count;
            JsonString.Append("{");
            JsonString.AppendFormat("\"total\":{0},", count);
            JsonString.AppendFormat("\"rows\":");
            if (dt == null)
                JsonString.Append("[]");
            else {
                JsonString.Append(ToJson((object)dt));
            }
            //JsonString.Append("[");
            if (dt != null && dt.Count > 0 && false)
            {

                for (int i = 0; i < dt.Count; i++)
                {
                    JsonString.Append("{");
                    System.Collections.Generic.Dictionary<string, object> DataRow = (System.Collections.Generic.Dictionary<string, object>)dt[i];
                    int j = 0;
                    foreach (System.Collections.Generic.KeyValuePair<string, object> key in DataRow)
                    {
                        if (j < DataRow.Count - 1)
                        {
                            JsonString.Append("\"" + key.Key.ToUpper() + "\":" + "\"" + StripNoJson(key.Value) + "\",");
                        }
                        else if (j == DataRow.Count - 1)
                        {
                            JsonString.Append("\"" + key.Key.ToUpper() + "\":" + "\"" + StripNoJson(key.Value) + "\"");
                        }
                        j++;
                    }

                    if (i == DataRow.Count - 1)
                    {
                        JsonString.Append("}");
                    }
                    else
                    {
                        JsonString.Append("},");
                    }
                }

            }
            //JsonString.Append("]");
            JsonString.Append("}");
            return JsonString.ToString();
        }
    }
    //自定义Json序列化规则
    public class NHibernateContractResolver : DefaultContractResolver
    {
        private string[] exceptMemberName;//显示指定需要序列化的属性的名称数组
        private bool IgnoreCollection = false;
        private static readonly MemberInfo[] NHibernateProxyInterfaceMembers = typeof(INHibernateProxy).GetMembers();

        public NHibernateContractResolver(string[] exceptMemberName,bool ignoreCollection)
        {
            this.exceptMemberName = exceptMemberName;
            this.IgnoreCollection = ignoreCollection;
        }
        protected override List<MemberInfo> GetSerializableMembers(Type objectType)
        {
            var members = new List<PropertyInfo>(objectType.GetProperties());//只出属性
            members.RemoveAll(memberInfo =>
                // (IsMemberNames(memberInfo))||
                (IsMemberPartOfNHibernateProxyInterface(memberInfo)) ||
                (IsMemberDynamicProxyMixin(memberInfo)) ||
                (IsMemberMarkedWithIgnoreAttribute(memberInfo, objectType)) ||
                    //(IsInheritedISet(memberInfo)) ||
                (IsInheritedEntity(memberInfo))
                );
            if (this.IgnoreCollection) {
                members.RemoveAll(memberInfo => IsInheritedISet(memberInfo) || memberInfo.PropertyType.Name == "List`1");
            }
            var actualMemberInfos = new List<MemberInfo>();
            foreach (var memberInfo in members)
            {
                var infos = memberInfo.DeclaringType.BaseType.GetMember(memberInfo.Name);
                actualMemberInfos.Add(infos.Length == 0 ? memberInfo : infos[0]);
                //Debug.WriteLine(memberInfo.Name);
            }
            return actualMemberInfos;
        }
        private static bool IsMemberDynamicProxyMixin(PropertyInfo memberInfo) //忽略nhib代理
        {
            return memberInfo.Name == "__interceptors";
        }

        private static bool IsMemberPartOfNHibernateProxyInterface(PropertyInfo memberInfo) //忽略nhib代理
        {
            return Array.Exists(NHibernateProxyInterfaceMembers, mi => memberInfo.Name == mi.Name);
        }

        private static bool IsMemberMarkedWithIgnoreAttribute(PropertyInfo memberInfo, Type objectType)//忽略带标记JsonIgnore的属性
        {
            var infos = typeof(INHibernateProxy).IsAssignableFrom(objectType) ?
                objectType.BaseType.GetMember(memberInfo.Name) :
                objectType.GetMember(memberInfo.Name);
            return infos[0].GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length > 0;
        }

        private bool IsExceptMember(PropertyInfo memberInfo)
        {
            if (exceptMemberName == null)
                return false;
            return Array.Exists(exceptMemberName, i => memberInfo.Name == i);
        }

        private bool IsInheritedISet(PropertyInfo memberInfo)//忽略掉数据类型为ISet<T>的属性
        {
            return (memberInfo.PropertyType.Name == "ISet`1" && !IsExceptMember(memberInfo));
        }

        private bool IsInheritedEntity(PropertyInfo memberInfo)//忽略掉数据类型为Entity的属性，传进来的例外字段名除外
        {
            return (FindBaseType(memberInfo.PropertyType).Name == "Entity" && !IsExceptMember(memberInfo));
        }
        private static Type FindBaseType(Type type)
        {
            if (!type.IsClass)
                return type;
            if (type.Name == "Entity" || type.Name == "Object")
            {
                return type;
            }
            return FindBaseType(type.BaseType);
        }
    }
}
